package com.lcf.aop;

import com.lcf.annotation.ExtTransactional;
import com.lcf.transaction.TransactionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.lang.reflect.Method;

/**
 * Created by lancf on 2019/4/25.
 */
@Component
@Aspect
public class ExtAopTransaction {

    @Autowired
    protected TransactionUtils transactionUtils;

    //jar包版本太低，不让使用pointCut
    @Pointcut("execution(* com.lcf.service.*.*.*(..))")
    private void point_(){}

    //异常通知
    @AfterThrowing("execution(* com.lcf.service.*.*.*(..))")
    public void afterThrowing() {
        System.out.println("事务回滚");
        //获取当前事务并回滚
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }

    //环绕通知
    @Around("execution(* com.lcf.service.*.*.*(..))")
    public void around(ProceedingJoinPoint proceed) throws Throwable {
        Method targetMethod = getTargetMethod(proceed);
        ExtTransactional extTransactional = targetMethod.getDeclaredAnnotation(ExtTransactional.class);

        //有这个注解，则开启事务
        TransactionStatus transactionStatus = begin(extTransactional);
        //代理调用方法,如果代理的方法抛出异常,则不会执行后面代码
        proceed.proceed();
        //提交事务
        commit(transactionStatus);

    }

    //获取目标代理对象
    private Method getTargetMethod(ProceedingJoinPoint proceed) throws NoSuchMethodException {
        //获取方法名称
        String methodName = proceed.getSignature().getName();
        //获取目标对象
        Class<?> targetClazz = proceed.getTarget().getClass();
        //获取目标对象类型
        MethodSignature signature = (MethodSignature) proceed.getSignature();
        Class[] parameterTypes = signature.getParameterTypes();
        //获取目标对象方法
        Method method = targetClazz.getMethod(methodName, parameterTypes);

        return method;
    }

    //开启事务
    private TransactionStatus begin(ExtTransactional extTransactional) {
        if (null != extTransactional) {

            TransactionStatus transactionStatus = transactionUtils.begin();
            return transactionStatus;
        }
        return null;
    }

    //提交事务
    private void commit(TransactionStatus transactionStatus) {
        if (null != transactionStatus) {
            System.out.println("提交事务");
            transactionUtils.commit(transactionStatus);
        }
    }

    //回滚事务
    private void rollback() {
        //获取当前事务进行回滚
        transactionUtils.rollback();
    }
}
